`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    22:02:09 01/27/2009 
// Design Name: 
// Module Name:    alu32 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module lac(c, gout, pout, Cin, g, p);
	output [1:0] c;
	output gout, pout;
	input Cin;
	input [1:0] g, p;
	
	assign c[0] = Cin;
	assign c[1] = g[0] | (p[0] & Cin);
	assign gout = g[1] | (p[1] & g[0]);
	assign pout = p[1] & p[0];
endmodule


module lac2(c, gout,pout, Cin, g ,p);
	output[3:0] c;
	output gout, pout;
	input Cin;
	input [3:0] g, p;
	
	wire [1:0] cint, gint, pint;
	
	lac leaf0
	(
		.c(c[1:0]),
		.gout(gint[0]),
		.pout(pint[0]),
		.Cin(cint[0]),
		.g(g[1:0]),
		.p(p[1:0])
	);
	
	lac leaf1
	(
		.c(c[3:2]),
		.gout(gint[1]),
		.pout(pint[1]),
		.Cin(cint[1]),
		.g(g[3:2]),
		.p(p[3:2])
	);
	
	lac root
	(
		.c(cint),
		.gout(gout),
		.pout(pout),
		.Cin(Cin),
		.g(gint),
		.p(pint)
	);
endmodule
	
module lac3(c, gout, pout, Cin, g, p);
	output [7:0] c;
	output gout, pout;
	input Cin;
	input [7:0] g, p;
	
	wire [1:0] cint, gint, pint;
	
	lac2 leaf0
	(
		.c(c[3:0]),
		.gout(gint[0]),
		.pout(pint[0]),
		.Cin(cint[0]),
		.g(g[3:0]),
		.p(p[3:0])
	);
	
	lac2 leaf1
	(
		.c(c[7:4]),
		.gout(gint[1]),
		.pout(pint[1]),
		.Cin(cint[1]),
		.g(g[7:4]),
		.p(p[7:4])
	);
	
lac root
	(
		.c(cint),
		.gout(gout),
		.pout(pout),
		.Cin(Cin),
		.g(gint),
		.p(pint)
	);
endmodule

module lac4(c, gout, pout, Cin, g, p);
	output [15:0] c;
	output gout, pout;
	input Cin;
	input [15:0] g, p;
	
	wire [1:0] cint, gint, pint;
	
	lac3 leaf0
	(
		.c(c[7:0]),
		.gout(gint[0]),
		.pout(pint[0]),
	.Cin(cint[0]),
		.g(g[7:0]),
		.p(p[7:0])
	);
	
	lac3 leaf1
	(
		.c(c[15:8]),
		.gout(gint[1]),
		.pout(pint[1]),
		.Cin(cint[1]),
		.g(g[15:8]),
		.p(p[15:8])
	);
	
	lac root
	(
		.c(cint),
		.gout(gout),
		.pout(pout),
		.Cin(Cin),
		.g(gint),
		.p(pint)
	);
endmodule

module lac5(c, gout, pout, Cin, g, p);
	output [31:0] c;
	output gout, pout;
	input Cin;
	input [31:0] g, p;
	
	wire [1:0] cint, gint, pint;
	
	lac4 leaf0
	(
		.c(c[15:0]),
		.gout(gint[0]),
		.pout(pint[0]),
		.Cin(cint[0]),
		.g(g[15:0]),
		.p(p[15:0])
	);
	
lac4 leaf1
	(
		.c(c[31:16]),
		.gout(gint[1]),
		.pout(pint[1]),
		.Cin(cint[1]),
		.g(g[31:16]),
		.p(p[31:16])
	);
	
	lac root
	(
		.c(cint),
		.gout(gout),
		.pout(pout),
		.Cin(Cin),
		.g(gint),
		.p(pint)
	);
endmodule

module alu_cell(d, g, p, a, b, c, S);
	output d, g, p;
	input a,b,c;
	input [3:0] S;
	
	wire cint, bint,m,x,y,z;
	
	assign bint = S[0] ^ b;
	assign g = a & bint;
	assign m = a | bint;
	assign p = a ^ bint;
	
	assign x = (S[2]&S[1]&g);
	assign y = (S[2]&(~S[1]))&((~m)&S[0]);
	assign z = (S[2]&(~S[1]))&(m&(~S[0]));
	assign cint = S[1] & c;
	assign d = (((p ^cint)&(~S[2]))    |   x   |   y   |  z)	;
endmodule

module alu32(out_d, Cout, V, a, b,Cin, S, shamt);
	output reg [31:0] out_d;
	output Cout, V;
	input [31:0] a, b;
	input Cin;
	input [3:0] S;
	
	input [4:0]shamt;
	wire [31:0] d;
	wire [31:0] c,g,p,b;
	wire gout, pout;
	
	
	assign bb = b;
	
	
		alu_cell alu_cell[31:0]
		(
			.d(d),
			.g(g),
			.p(p),
			.a(a),
			.b(b),
			.c(c),
			.S(S)
		);
		
		lac5 lac
		(
			.c(c),
			.gout(gout),
			.pout(pout),
			.Cin(Cin),
			.g(g),
			.p(p)
		);
		assign Cout = gout | (pout & Cin);
		assign V = Cout ^ c[31];
		
	always @(*)
	    case(S)
	    4'b1000: out_d <= bb >> shamt;
	    4'b1001: out_d <= bb << shamt;
	    default: out_d <= d;
		endcase
		
		//assign out_d = d;
endmodule